package backend;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.application.ApplicationContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.AbstractListModel;

public class Ranking<T> {
    private String file = null;
    private ApplicationContext ctxt;
    private MapListModel<T> listModel = null;

    public Ranking(String file, ApplicationContext ctxt){
        this.file=file;
        this.ctxt=ctxt;
        this.listModel = new MapListModel<T>();
        try {
            loadMap();
        }catch(NullPointerException e){
        } catch (IOException ex) {
        }
    }

    public void addKeyValueEntry(T key) {
	listModel.put(key);
    }

    public void loadMap() throws IOException {
	Object map = this.ctxt.getLocalStorage().load(file);
	listModel.setMap((LinkedHashMap<T, Integer>)map);
    }

    public LinkedHashMap<T, Integer> getMap() {
        return listModel.getMap();
    }

    public HashMap<T, Integer> getTopRank(){
        Integer val[] = new Integer[listModel.getMap().size()];
        Object keys[] = null;

        val = listModel.getMap().values().toArray(val);        
        int length=val.length>10?10:val.length; //la longitud, o 10 o la cant que haya
        
        if(length==10){
            Arrays.sort(val); //los ordeno de menor a mayor
            Integer out[] = new Integer[length];
            HashMap<T, Integer> list= new HashMap<T, Integer>();

            for(int j=0, i=val.length-1; j<length; j++, i-- ){
                out[j]=val[i];
            }
            keys = listModel.getKeys().toArray();
            int aux=0;
            for(Object key:keys){
                aux=listModel.getMap().get((T)key);
                for(int i=0;i<out.length;i++){
                    if(out[i]==aux){
                        list.put((T)key, aux);
                        out[i]=-1;
                        i=out.length;
                    }
                }
            }
            return list;
        }
        return listModel.getMap();
    }

    public void saveMap() throws IOException  {
	LinkedHashMap<T, Integer> map = listModel.getMap();
	this.ctxt.getLocalStorage().save(map, file);
    }

    private static class MapListModel<T> extends AbstractListModel {
	private final LinkedHashMap<T, Integer> map = new LinkedHashMap<T, Integer>();
	private List<T> keys = null;
	private List<T> getKeys() {
	    if (keys == null) {
		keys = new ArrayList<T>(map.keySet());
	    }
	    return keys;
	}
	public void put(T key) {
	    int index = -1;
            int value=1;
	    if (map.containsKey(key)) {
		index = getKeys().indexOf(key);
                value=map.get(key)+1;
	    }
	    else {
		index = map.size();
		keys = null;
	    }
	    map.put(key, value);
	    fireContentsChanged(this, index, index);
	}
	public void clear() {
	    if (map.size() > 0) {
		int lastIndex = map.size() - 1;
		map.clear();
		keys = null;
		fireIntervalRemoved(this, 0, lastIndex);
	    }
	}

        public LinkedHashMap<T, Integer> getMap() {
	    return new LinkedHashMap<T, Integer>(map);
	}

        public void setMap(LinkedHashMap<T, Integer> newMap) {
	    int oldLastIndex = Math.max(map.size() - 1, 0);
	    map.clear();
	    map.putAll(newMap);
	    int newLastIndex = Math.max(map.size() - 1, 0);
	    fireContentsChanged(this, 0, Math.max(oldLastIndex, newLastIndex));
	}
        @Override
	public int getSize() {
	    return map.size();
	}
        @Override
	public Object getElementAt(int index) {
	    T key = getKeys().get(index);
	    return key + " = " + map.get(key);
	}
    }
}
